package com.easyidea.its.web.result;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import jxl.Workbook;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import com.easyidea.its.util.excel.ExcelUtil;
import com.easyidea.its.util.excel.SheetDefinition;
import com.easyidea.its.util.excel.WorkbookDefinition;
import com.infowarelab.common.log.Log;
import com.infowarelab.common.log.LogFactory;
import com.opensymphony.util.BeanUtils;
import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.webwork.dispatcher.StreamResult;
import com.opensymphony.webwork.views.util.ResourceUtil;
import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.ActionInvocation;
import com.opensymphony.xwork.config.ConfigurationException;
import com.opensymphony.xwork.util.OgnlValueStack;

public class ExcelResult extends StreamResult {
	private static final long serialVersionUID = 2619137936475841357L;
	protected static final Log log = LogFactory.getLog(ExcelResult.class);
	
	private String rowNum;
	
	public String getRowNum() {
		return rowNum;
	}

	public void setRowNum(String rowNum) {
		this.rowNum = rowNum;
	}

	@Override
	protected void doExecute(String location, ActionInvocation invocation)
			throws Exception {
		 String templatePath = "";
		 if (!location.startsWith("/")) {
				ActionContext ctx = invocation.getInvocationContext();
				
				HttpServletRequest req = (HttpServletRequest) ctx
						.get(ServletActionContext.HTTP_REQUEST);
				String base = ResourceUtil.getResourceBase(req);
				location = base + "/" + location;
			}
			String[] paths = location.split(";");
			templatePath = paths[0];
			location = paths[1];
			
		 	ServletContext servletContext = ServletActionContext
					.getServletContext();
			HttpServletRequest request = ServletActionContext.getRequest();
			HttpServletResponse response = ServletActionContext.getResponse();
			OgnlValueStack stack = (OgnlValueStack)ServletActionContext.getContext()
					.getValueStack();
			
			 // Set the content-disposition
	        if (contentDisposition != null && !contentDisposition.equals("inline")) {
	        	response.addHeader("Content-disposition", conditionalParse(contentDisposition, invocation));
	        }else {
	    		response.setContentType("text/xml;charset=UTF-8");

	    		String fileName = java.net.URLEncoder.encode("过车列表","UTF8") + ".xls";
	    		response.addHeader("Content-Disposition", "attachment;filename="+fileName);
	        }
	        response.setContentType("application/vnd.ms-excel");
	        
			Object action = null;
			if (invocation != null)
				action = invocation.getAction(); // Added for NullPointException
			Workbook workBook = Workbook.getWorkbook(new File(servletContext.getRealPath(templatePath)));
 			WorkbookDefinition def = createWorkbookDefinitionFromXml(location, stack, action, servletContext, request, response);
			ExcelUtil.writeWorkbook(response.getOutputStream(), def,workBook,rowNum);
			
	}
		
	private WorkbookDefinition createWorkbookDefinitionFromXml(
			String finalLocation, OgnlValueStack stack, Object action,
			ServletContext servletContext, HttpServletRequest request,
			HttpServletResponse response) {
		
			finalLocation = servletContext.getRealPath(finalLocation);
            Document doc = buildDoc(finalLocation);
            
            return createDefFromDoc(doc,stack, action, servletContext, request, response);
            
	}

	private WorkbookDefinition createDefFromDoc(Document doc, OgnlValueStack stack, Object action,
			ServletContext servletContext, HttpServletRequest request,
			HttpServletResponse response) {

		WorkbookDefinition def = new WorkbookDefinition();
		
		Element rootElement = doc.getDocumentElement();
		NodeList children = rootElement.getChildNodes();
		int childSize = children.getLength();

		for (int i = 0; i < childSize; i++) {
		    Node childNode = children.item(i);

		    if (childNode instanceof Element) {
		        Element child = (Element) childNode;

		        final String nodeName = child.getNodeName();

		        if (nodeName.equals("sheet")) {
		        	SheetDefinition sheetDef = createSheetDef(child, stack, action, servletContext, request, response);
		        	def.addSheetDef(sheetDef);
		        }
		    }
		}
		return def;
	}
	
	private SheetDefinition createSheetDef(Element child, OgnlValueStack stack, Object action, ServletContext servletContext, HttpServletRequest request, HttpServletResponse response) {
		// TODO Auto-generated method stub
		String sheetName = child.getAttribute("name");
		
		Collection entitys = null;
		List<String> columnList = new ArrayList<String>();
		List<String> titleList = new ArrayList<String>();
		
		NodeList children = child.getElementsByTagName("entityName");
	    Node childNode = children.item(0);
    	String entityPropertyName = childNode.getTextContent();
    	Object obj = BeanUtils.getValue(action, entityPropertyName);
    	if (obj instanceof Collection) {
			entitys = (Collection) obj;
		}
    	children = child.getElementsByTagName("column");
		int childSize = children.getLength();

		for (int i = 0; i < childSize; i++) {
		    Element ele = (Element)children.item(i);
		    columnList.add(ele.getTextContent());
		    titleList.add(ele.getAttribute("title"));
		}
    	
		
		SheetDefinition sheetDef = new SheetDefinition(sheetName, entitys, columnList.toArray(new String[]{}), titleList.toArray(new String[]{}));
		return sheetDef;
	}

	private Document buildDoc(String fileName) {

		Document doc = null;
		InputStream is = null;
		
		;

		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setValidating(false);
			dbf.setNamespaceAware(true);

			DocumentBuilder db = dbf.newDocumentBuilder();

			db.setErrorHandler(new ErrorHandler() {
				public void warning(SAXParseException exception) {
				}

				public void error(SAXParseException exception)
						throws SAXException {
					log.error(exception.getMessage() + " at ("
							+ exception.getLineNumber() + ":"
							+ exception.getColumnNumber() + ")");
					throw exception;
				}

				public void fatalError(SAXParseException exception)
						throws SAXException {
					log.fatal(exception.getMessage() + " at ("
							+ exception.getLineNumber() + ":"
							+ exception.getColumnNumber() + ")");
					throw exception;
				}
			});


			is = getInputStream(fileName);

			if (is == null) {
				throw new Exception("Could not open file " + fileName);
			}

			doc = db.parse(is);
		} catch (Exception e) {
			final String s = "Caught exception while loading file " + fileName;
			log.error(s, e);
			throw new ConfigurationException(s, e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					log.error("Unable to close input stream", e);
				}
			}
		}
		return doc;
	}

    protected InputStream getInputStream(String fileName) {
    	FileInputStream fis = null;
    	try {
    		fis = new FileInputStream(fileName);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return fis; 
    }
	

}
